package com.yumo.kangchenjunga.activity;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.StringMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import com.yumo.kangchenjunga.coupon.v1.CouponService;
import com.yumo.kangchenjunga.coupon.v1.ImportResult;
import com.yumo.kangchenjunga.log.LogEntity;
import com.yumo.kangchenjunga.log.LogService;
import com.yumo.kangchenjunga.security.CustomUserDetails;

@Service
public class ActivityService {

	@Autowired
	private ActivityRepository repository;
	@Autowired
	private CouponService couponService;
	@Autowired
	private LogService logService;
	@Autowired
	private JdbcTemplate jdbcTemplate;

	public Activity newActivity(Activity activity) {
		activity.setCustomerLevels("1,2,3,4");
		activity.quantity = 1;

		var result = Activity.newActivity(repository, activity);

		logService.log(genLog(result, "新建", "成功",
				String.format("创建权益成功 id: %d, title: '%s'", result.getId(), result.title)));

		return result;
	}

	public Activity queryById(int id) throws NoSuchActivityException {
		return repository.findById(id).orElseThrow(NoSuchActivityException::new);
	}

	public void deleteActivity(int id)
			throws ActivityAlreadyIssuedCouponException {
		Optional<Activity> row = repository.findById(id);

		if (row.isPresent()) {
			var activity = row.get();

			if (couponService.notExistsCoupon(activity)) {
				repository.deleteById(id);

				logService.log(genLog(activity, "删除", "成功",
						String.format("删除权益成功 id: %d, title: '%s'", activity.getId(), activity.title)));
			} else {
				logService.log(genLog(activity, "删除", "失败",
						String.format("删除权益失败 id: %d, title: '%s'，权益已有优惠券。", activity.getId(), activity.title)));

				throw new ActivityAlreadyIssuedCouponException("The coupons for the activity has been issued");
			}
		}
	}

	public Activity modifyActivity(int id, Activity activity)
			throws NoSuchActivityException, ActivityAlreadyIssuedCouponException {
		Optional<Activity> row = repository.findById(id);

		if (row.isPresent()) {
			if (couponService.notExistsCoupon(row.get())) {
				logService.log(genLog(activity, "修改", "成功",
						String.format("成功修改权益 id: %d, title: '%s'", activity.getId(), activity.title)));
				activity.customerLevels = row.get().customerLevels;
				activity.quantity = row.get().quantity;
				return repository.save(activity);
			} else {
				throw new ActivityAlreadyIssuedCouponException("The coupons for the activity has been issued");
			}
		}

		throw new NoSuchActivityException();
	}

	public List<Activity> list() {
		return repository.findAll();
	}

	public List<Activity> listByCompanyId(int companyId) {
		return repository.findByCompanyId(companyId);
	}

	public Page<Activity> page(Pageable pageable) {
		return repository.findAll(pageable);
	}

	public Page<Activity> query(Activity activity, Pageable pageable) {
		ExampleMatcher matcher = ExampleMatcher.matchingAll().withIgnoreCase()
				.withIgnorePaths("id", "customerLevels", "status")
				.withStringMatcher(StringMatcher.CONTAINING);
		Example<Activity> example = Example.of(activity, matcher);

		return repository.findAll(example, pageable);
	}

	@Transactional
	public void interrupt(int activityId, boolean ignoreCoupons) {
		Optional<Activity> activity = repository.findById(activityId);

		if (activity.isPresent()) {
			repository.updateStatus(activityId, Status.INTERRUPTED);

			if (ignoreCoupons) {
				couponService.interrupt(activity.get());
			}
		}
	}

	public boolean existsByCompanyId(int companyId) {
		return repository.existsByCompanyId(companyId);
	}

	public ImportResult importCoupon(InputStream inputStream, int activityId)
			throws IOException, NoSuchActivityException {
		Optional<Activity> activity = repository.findById(activityId);

		if (activity.isPresent()) {
			return couponService.importCoupon(inputStream, activity.get());
		}

		throw new NoSuchActivityException();
	}

	public Activity findById(int activityId) throws NoSuchActivityException {
		return repository.findById(activityId).orElseThrow(NoSuchActivityException::new);
	}

	private LogEntity genLog(Activity activity, String op, String result, String detail) {
		var user = (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		var log = new LogEntity();

		log.activityId = activity.getId();
		log.activityTitle = activity.title;
		log.companyId = activity.company.getId();
		log.companyName = activity.company.name;
		log.op = op;
		log.opDetail = detail;
		log.opObject = "权益";
		log.opResult = result;
		log.opUserId = user.getId();
		log.opUsername = user.getUsername();

		return log;
	}

	public List<Integer> listActivityStore(int activityId) {
		var sql = String.format("select store_id from activity_store_map where activity_id = %d", activityId);

		return jdbcTemplate.queryForList(sql, Integer.class);
	}

	public void modifyActivityStore(int activityId, List<Integer> storeIds) throws NoSuchActivityException {
		try {
			Activity activity = repository.findById(activityId).orElseThrow();
			var sqls = new ArrayList<String>();

			Objects.requireNonNull(activity);
			sqls.add(String.format("delete from activity_store_map where activity_id = %d", activityId));
			storeIds.forEach(it -> sqls.add(String
					.format("insert into activity_store_map (activity_id, store_id) values (%d, %d)", activityId, it)));

			jdbcTemplate.batchUpdate(sqls.toArray(new String[sqls.size()]));
		} catch (NoSuchElementException e) {
			throw new NoSuchActivityException();
		}
	}

}
